home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
scope
/
001-025
/
scopedisk1
/
semaphorestutor
/
sem.doc
< prev
next >
Wrap
Text File
|
1995-03-18
|
6KB
|
173 lines
I've been looking through the Autodocs on message & signal semaphores
and I find them to be a little bit lacking (I know, this has been
mentioned before). So I was hoping that I might clarify the
use of them just a bit. These programs demonstrate what I think is
going on, I invite you all to try to find problems with them... They seem
OK to me but semaphores in any O/S are a really touchy area.
----
Message based semaphores (usually refered to as just 'Semaphores') make use
of the Message sending/receiving/waiting protocols. In order to use
them you must initialize a 'struct Semaphore' if you examine just what
a struct Semaphore is you'll see that it is defined as
struct Semaphore {
struct MsgPort sm_MsgPort;
WORD sm_Bids;
}
(it's in <exec/semaphores.h> like all of the semaphore definitions).
To initialize it, you must allocate the memory for the structure and
then do all of the usual MsgPort initialization things. Normally
CreatePort() does all of this for you but you can't use it as you have
do to a slightly different initialization for a semaphore. See the
CreateSemaphore() function in the msgsem example. You can make a
semaphore public by making its MsgPort public (i.e. giving the MsgPort
a name & priority and using AddPort() to add the port to the system list
of named ports). You can then find such a semaphore by using the FindPort()
call... To remove the semaphore from the system you have do remove it from
the public port list using RemPort() (iff you added it to that list) and
then simply free the memory allocated for the structure.
Assuming you have created the Semaphore, to use it you must allocate a
message (to be used as your 'bid' for the semaphore) and port that this
message will be sent to. Initialize the mn_ReplyPort field of your
message to point to your port. You then use these two functions
to lock/unlock the semaphore.
Procure(Semaphore, BidMessage)
struct Semaphore *Semaphore;
struct Message *BidMessage;
Procure() returns true if the semaphore can be locked for your
use immediately. If the semaphore cannot be locked, your
bid is queued up and when it becomes free your BidMessage
will be sent the the port you allocated (the one that nm_ReplyPort
in the BidMessage is supposed to point to). So if you need
to get the Semaphore and you can't go on any further without
it you must do something like
if (!Procure(semaphore,message)) {
WaitPort(message->mn_ReplyPort);
GetMsg(message->nm_ReplyPort);
}
... put code that needs the semaphore here ...
This assumes that there is only one semaphore using this port
for it's replies. Otherwise you have to be more complicated.
Vacate(Semaphore)
struct Semaphore *Semaphore;
Vacate() unlocks the semaphore so that some other Procure()
will succeed or if there is an outstanding bid then the
bid message will sent to the appropriate port.
So much for straight Semaphores. Now onto SignalSemaphores.
----
SignalSemaphores seem much easier to use on the surface only they
are slightly broken which makes up for this. The AddSemaphore(),
RemSemaphore() and FindSemaphore() calls all need special attention
as they don't work as advertised in the Autodocs. Other than this
difficulty, signal semaphores are very easy to deal with as
there are no painful initialization rituals to remember as with
message semaphores above... just allocate enough memory for the
SignalSemaphore and you're off to the races.
InitSemaphore(SignalSemaphore)
struct SignalSemaphore *SignalSemaphore;
Initializes a signal semaphore structure. Use this function
for "private" semaphores (i.e. known only to tasks that
have easy access to the creator's memory).
AddSemaphore(SignalSemaphore)
struct SignalSemaphore *SignalSemaphore;
Adds the semaphore to the system list of semaphores. You
must fill in the ss_Link.ln_{Type,Name,Pri} fields before
calling this. AddSemaphore() calls InitSemaphore() so
you don't need to do call this yourself if you use AddSemaphore().
N.B. The Exec version of this function seems to be broken.
Use Dale's "hand crafted" version instead. (it's just a
InitSemaphore() call followed by an atomic Enqueue on the
system signal semaphore list). See example.
RemSemaphore(SignalSemaphore)
struct SignalSemaphore *SignalSemaphore;
Removes the given semaphore from the system list of public
semaphores.
N.B. The amiga.lib and c[32].lib bindings for this function
are broken. You must include your own bindings for this
to work. See example.
struct SignalSemaphore *FindSemaphore(name)
char *name;
Search the system list for semaphores for one with the given
name. Returns a pointer to the semaphore if one is found,
NULL otherwise.
N.B. The amiga.lib and c[32].lib bindings for this function
are broken. You must include your own bindings for this
to work. See example.
ObtainSemaphore(SignalSemaphore)
struct SignalSemaphore *SignalSemaphore;
This function locks the given semaphore for your use. If the
semaphore is currently in use by someone else it blocks until
it is Release'd by the current owner. A nesting count is
maintained if you try to Obtain a semaphore that you already
have.
ReleaseSemaphore(SignalSemaphore)
struct SignalSemaphore *SignalSemaphore;
This function frees the given semaphore for use by someone
else. If you Obtained the semaphore more than once the
the nesting count is simply decremented rather than
actually Releasing the semaphore. Bad things happen if
you Release more times than you Obtain.
AttemptSemaphore(SignalSemaphore)
struct SignalSemaphore *SignalSemaphore;
This function tries to Obtain the semaphore provided. If this
can be done it locks the semaphore and returns true. If the
semaphore is currently in use by someone else it returns false.
Use this function if you don't want to block your task waiting
for a semaphore.
ObtainSemaphoreList(SemaphoreList)
struct SemaphoreList *SemaphoreList;
ReleaseSemaphoreList(SemaphoreList)
struct SemaphoreList *SemaphoreList;
Haven't played with these two yet... They're used for locking
several semaphores in one atomic action. This ability can
be used to prevent deadlock.
----
Note:
The Kernel doesn't seem to do any kind of deadlock prevention
or recovery. This means you have to decide for yourself if
deadlock is an issue in your application. There are several
good books which deal with deadlock avoidance and so forth
so I won't go into that here.